1 Ejercicio 1

En este link encontraréis los datos de un libro de recetas en formato zip. La tarea consiste en buscar reglas de asociación a partir de estos datos. ¿Es posible encontrar una regla para todas las recetas de pescado? ¿O de recetas picantes? Jugar con los datos, intenta encontrar alguna regla “interesante”.

1.1 Busqueda de reglas de asociación

Una vez se han limpiado los datos desde el documento “Limpieza_Recetas.Rmd”, los cargamos en forma de transacción con la función read.transactions.

recetas <- read.transactions("recipe_ingredients_transactions.csv", header = FALSE, rm.duplicates = FALSE, sep = ";")

Veamos como son los dos primeros elementos delconjunto de transacciones.

inspect(recetas[1:2]) 
##     items                
## [1] {apples,             
##      dill pickles,       
##      lemons,             
##      oranges,            
##      saladitos}          
## [2] {basil,              
##      cloves garlic,      
##      corn,               
##      favorite seasonings,
##      hamburger,          
##      italian seasoning,  
##      kidney beans,       
##      mild,               
##      mushrooms,          
##      onion,              
##      pepper,             
##      red pepper,         
##      tomato sauce,       
##      uncooked pasta}

Observemos cuales son los itemsets más frecuentes con un soporte de \(0.12\).

frequentItems <- eclat(recetas, parameter = list(support = 0.13))
## Eclat
## 
## parameter specification:
##  tidLists support minlen maxlen            target  ext
##     FALSE    0.13      1     10 frequent itemsets TRUE
## 
## algorithmic control:
##  sparse sort verbose
##       7   -2    TRUE
## 
## Absolute minimum support count: 193 
## 
## create itemset ... 
## set transactions ...[4014 item(s), 1489 transaction(s)] done [0.01s].
## sorting and recoding items ... [6 item(s)] done [0.00s].
## creating bit matrix ... [6 row(s), 1489 column(s)] done [0.00s].
## writing  ... [6 set(s)] done [0.00s].
## Creating S4 object  ... done [0.00s].
inspect(frequentItems)
##     items    support   transIdenticalToItemsets count
## [1] {salt}   0.3868368 576                      576  
## [2] {sugar}  0.2558764 381                      381  
## [3] {butter} 0.2014775 300                      300  
## [4] {water}  0.1927468 287                      287  
## [5] {flour}  0.1450638 216                      216  
## [6] {milk}   0.1383479 206                      206

Vemos que el itemset salt es el que mayor soporte tiene. Observemos gáficamente los 15 itemsets más frecuentes.

itemFrequencyPlot(recetas, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")  

Como hemos dicho antes, el itemset salt es el más frecuente. Es seguido por los itemsets sugar y water. Intentemos ahora determinar reglas de asociación para las recetas de pescado. Para ello haremos una lista con nombres de pescados para seleecionar aquellas que los contengan.

Seleccionaremos los siguientes pescados: “hake”, “shark”, “monkfish”, “rooster”, “cod”, “turbot”, “sole fish”, “fish”, “bass”, “anchovy”, “sardine”, “salmon”, “mackerel”, “herring”, “tuna”, “golden fish”, “trout”, “sea bream”, “seafood”, “snapper”, “bluefish”, “croaker”, “flounder”.

Tambien limpiaremos el conjunto de datos para el proximo apartado de las recetas picantes. Aqui seleccionaremos las palabras “red-hot”, “spicy”, “hot”, “peppery”, “racy”, “piquancy”.

Lo que haremos será al final guardar en dos documentos diferentes las recetas de pescados y las recetas picantes.

lista_pescados <- "hake|shark|monkfish|rooster|cod|turbot|sole fish|fish|bass|anchovy|sardine|salmon|mackerel|herring|tuna|golden fish|trout|sea bream|seafood|snapper|bluefish|croaker|flounder"

lista_picantes <- "red-hot|spicy|hot|peppery|racy|piquancy"

transformacion <- as(recetas, "data.frame") #Pasamos a data frame para la limpieza

transformacion$items <- as.character(transformacion$items) #Convertimos en caracter

transformacion$items <- substr(transformacion$items, 2, nchar(transformacion$items)-1) #Eliminamos las llaves que han aparecido


#### Para los pescados

pescados <- filter(transformacion, str_detect(items,lista_pescados)) #Buscamos los nombres de pescados en los ingredientes

pescados <- str_split_fixed(pescados$items, ",", n=Inf) #Separamos los ingredientes en columnas

for (i in 1:nrow(pescados)) { #Cambiamos los elementos vacios por NA
  for (j in 1:ncol(pescados)) {
    if (pescados[i,j] == "" ) {
      pescados[i,j] = NA
    }
  }
}

write.csv(pescados, file = "recetas_pescados.csv", row.names = FALSE, col.names = FALSE) #Guardamos el resultado en un documento .csv

#### Para las picantes

nombres_recetas <- read.csv2("nombres_recetas.csv", header = FALSE) #Cargamos el nombre de las recetas

indices <- which(str_detect(nombres_recetas[,1],lista_picantes)) #Buscamos las que tengas palabras que indiquen comida picante

picantes <- transformacion[indices, ] #Seleccionamos los ingredientes de las recetas picantes

picantes <- str_split_fixed(picantes, ",", n=Inf) #Separamos los ingredientes en columnas

for (i in 1:nrow(picantes)) { #Cambiamos los elementos vacios por NA
  for (j in 1:ncol(picantes)) {
    if (picantes[i,j] == "" ) {
      picantes[i,j] = NA
    }
  }
}

write.csv(picantes, file = "recetas_picantes.csv", row.names = FALSE, col.names = FALSE) #Guardamos el resultado en un documento .csv

Cargamos el conjunto de datos de las recetas de pescados.

recetas_pescados <- read.transactions("recetas_pescados.csv", sep = ",", skip = 1, rm.duplicates = FALSE)
## Warning in asMethod(object): removing duplicated items in transactions
inspect(recetas_pescados[1:2])
##     items                  
## [1] {best foods mayonnaise,
##      carrots,              
##      celery,               
##      frozen peas,          
##      hard boiled eggs,     
##      macaroni,             
##      maui onion,           
##      milk,                 
##      salad potatoes,       
##      salt pepper,          
##      tuna}                 
## [2] {breadcrumbs,          
##      butter,               
##      fish steaks,          
##      milk,                 
##      salt,                 
##      sliced lemon,         
##      watercress}

Una vez tenemos solo las recetas que contienen pescado, vamos a ver cuales son los itemsets más frecuentes en ellas.

itemFrequencyPlot(recetas_pescados, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")

Los itemsets más frecuentes son la sal, la matequilla y la cebolla.

Pasamos a buscar reglas de asociación para las recetas de pescados. Consideraremos las reglas con antecedente vacío ya que corresponden a que un ingrediente es pescado.

Grules_pescado <- apriori(recetas_pescados, parameter = list(supp = 0.05, conf = 0.1, minlen=1), control = list (verbose=F))
Grules_conf_pescado <- sort (Grules_pescado, by="support", decreasing=TRUE)
inspect(Grules_conf_pescado)
##      lhs                 rhs              support    confidence coverage  
## [1]  {}               => {salt}           0.28333333 0.2833333  1.00000000
## [2]  {}               => {butter}         0.23333333 0.2333333  1.00000000
## [3]  {}               => {onion}          0.18333333 0.1833333  1.00000000
## [4]  {}               => {water}          0.16666667 0.1666667  1.00000000
## [5]  {}               => {lemon juice}    0.15000000 0.1500000  1.00000000
## [6]  {}               => {milk}           0.11666667 0.1166667  1.00000000
## [7]  {}               => {white wine}     0.11666667 0.1166667  1.00000000
## [8]  {}               => {olive}          0.11666667 0.1166667  1.00000000
## [9]  {onion}          => {salt}           0.11666667 0.6363636  0.18333333
## [10] {salt}           => {onion}          0.11666667 0.4117647  0.28333333
## [11] {}               => {flour}          0.10000000 0.1000000  1.00000000
## [12] {butter}         => {salt}           0.10000000 0.4285714  0.23333333
## [13] {salt}           => {butter}         0.10000000 0.3529412  0.28333333
## [14] {lemon juice}    => {salt}           0.08333333 0.5555556  0.15000000
## [15] {salt}           => {lemon juice}    0.08333333 0.2941176  0.28333333
## [16] {water}          => {onion}          0.08333333 0.5000000  0.16666667
## [17] {onion}          => {water}          0.08333333 0.4545455  0.18333333
## [18] {water}          => {salt}           0.08333333 0.5000000  0.16666667
## [19] {salt}           => {water}          0.08333333 0.2941176  0.28333333
## [20] {flour}          => {butter}         0.06666667 0.6666667  0.10000000
## [21] {butter}         => {flour}          0.06666667 0.2857143  0.23333333
## [22] {lime juice}     => {fish sauce}     0.05000000 1.0000000  0.05000000
## [23] {fish sauce}     => {lime juice}     0.05000000 0.6000000  0.08333333
## [24] {tuna}           => {milk}           0.05000000 0.6000000  0.08333333
## [25] {milk}           => {tuna}           0.05000000 0.4285714  0.11666667
## [26] {pepper}         => {salt}           0.05000000 0.6000000  0.08333333
## [27] {salt}           => {pepper}         0.05000000 0.1764706  0.28333333
## [28] {leaf}           => {butter}         0.05000000 1.0000000  0.05000000
## [29] {butter}         => {leaf}           0.05000000 0.2142857  0.23333333
## [30] {sugar}          => {fish sauce}     0.05000000 0.6000000  0.08333333
## [31] {fish sauce}     => {sugar}          0.05000000 0.6000000  0.08333333
## [32] {cayenne pepper} => {salt}           0.05000000 0.7500000  0.06666667
## [33] {salt}           => {cayenne pepper} 0.05000000 0.1764706  0.28333333
## [34] {fish stock}     => {butter}         0.05000000 0.7500000  0.06666667
## [35] {butter}         => {fish stock}     0.05000000 0.2142857  0.23333333
## [36] {fish stock}     => {salt}           0.05000000 0.7500000  0.06666667
## [37] {salt}           => {fish stock}     0.05000000 0.1764706  0.28333333
## [38] {milk}           => {butter}         0.05000000 0.4285714  0.11666667
## [39] {butter}         => {milk}           0.05000000 0.2142857  0.23333333
## [40] {parsley}        => {flour}          0.05000000 0.7500000  0.06666667
## [41] {flour}          => {parsley}        0.05000000 0.5000000  0.10000000
## [42] {white wine}     => {butter}         0.05000000 0.4285714  0.11666667
## [43] {butter}         => {white wine}     0.05000000 0.2142857  0.23333333
## [44] {white wine}     => {salt}           0.05000000 0.4285714  0.11666667
## [45] {salt}           => {white wine}     0.05000000 0.1764706  0.28333333
## [46] {lemon juice}    => {onion}          0.05000000 0.3333333  0.15000000
## [47] {onion}          => {lemon juice}    0.05000000 0.2727273  0.18333333
## [48] {lemon juice}    => {butter}         0.05000000 0.3333333  0.15000000
## [49] {butter}         => {lemon juice}    0.05000000 0.2142857  0.23333333
## [50] {flour}          => {water}          0.05000000 0.5000000  0.10000000
## [51] {water}          => {flour}          0.05000000 0.3000000  0.16666667
## [52] {flour}          => {salt}           0.05000000 0.5000000  0.10000000
## [53] {salt}           => {flour}          0.05000000 0.1764706  0.28333333
## [54] {olive}          => {salt}           0.05000000 0.4285714  0.11666667
## [55] {salt}           => {olive}          0.05000000 0.1764706  0.28333333
## [56] {onion}          => {butter}         0.05000000 0.2727273  0.18333333
## [57] {butter}         => {onion}          0.05000000 0.2142857  0.23333333
## [58] {butter,flour}   => {salt}           0.05000000 0.7500000  0.06666667
## [59] {flour,salt}     => {butter}         0.05000000 1.0000000  0.05000000
## [60] {butter,salt}    => {flour}          0.05000000 0.5000000  0.10000000
## [61] {onion,water}    => {salt}           0.05000000 0.6000000  0.08333333
## [62] {salt,water}     => {onion}          0.05000000 0.6000000  0.08333333
## [63] {onion,salt}     => {water}          0.05000000 0.4285714  0.11666667
##      lift      count
## [1]   1.000000 17   
## [2]   1.000000 14   
## [3]   1.000000 11   
## [4]   1.000000 10   
## [5]   1.000000  9   
## [6]   1.000000  7   
## [7]   1.000000  7   
## [8]   1.000000  7   
## [9]   2.245989  7   
## [10]  2.245989  7   
## [11]  1.000000  6   
## [12]  1.512605  6   
## [13]  1.512605  6   
## [14]  1.960784  5   
## [15]  1.960784  5   
## [16]  2.727273  5   
## [17]  2.727273  5   
## [18]  1.764706  5   
## [19]  1.764706  5   
## [20]  2.857143  4   
## [21]  2.857143  4   
## [22] 12.000000  3   
## [23] 12.000000  3   
## [24]  5.142857  3   
## [25]  5.142857  3   
## [26]  2.117647  3   
## [27]  2.117647  3   
## [28]  4.285714  3   
## [29]  4.285714  3   
## [30]  7.200000  3   
## [31]  7.200000  3   
## [32]  2.647059  3   
## [33]  2.647059  3   
## [34]  3.214286  3   
## [35]  3.214286  3   
## [36]  2.647059  3   
## [37]  2.647059  3   
## [38]  1.836735  3   
## [39]  1.836735  3   
## [40]  7.500000  3   
## [41]  7.500000  3   
## [42]  1.836735  3   
## [43]  1.836735  3   
## [44]  1.512605  3   
## [45]  1.512605  3   
## [46]  1.818182  3   
## [47]  1.818182  3   
## [48]  1.428571  3   
## [49]  1.428571  3   
## [50]  3.000000  3   
## [51]  3.000000  3   
## [52]  1.764706  3   
## [53]  1.764706  3   
## [54]  1.512605  3   
## [55]  1.512605  3   
## [56]  1.168831  3   
## [57]  1.168831  3   
## [58]  2.647059  3   
## [59]  4.285714  3   
## [60]  5.000000  3   
## [61]  2.117647  3   
## [62]  3.272727  3   
## [63]  2.571429  3

Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(63\) reglas de asociación. Podemos observar que las primera reglas con mayor soporte son aquellas que el antecedente es vacío. Esto nos dice que las recetas de pescado llevan sal con un soporte de \(0.28333333\) y llevan mantequilla con un soporte igual al anterior.

La primera regla con antecedente no vacío y mayor soporte es:

\[ \mbox{(Si es una receta de pescado y lleva cebolla)} \rightarrow \ \mbox{(Lleva sal)} \]

Veamos estas reglas obtenidas pero ordenadas por mayor confianza.

Grules_conf_pescado <- sort (Grules_pescado, by="confidence", decreasing=TRUE)
inspect(Grules_conf_pescado)
##      lhs                 rhs              support    confidence coverage  
## [1]  {lime juice}     => {fish sauce}     0.05000000 1.0000000  0.05000000
## [2]  {leaf}           => {butter}         0.05000000 1.0000000  0.05000000
## [3]  {flour,salt}     => {butter}         0.05000000 1.0000000  0.05000000
## [4]  {cayenne pepper} => {salt}           0.05000000 0.7500000  0.06666667
## [5]  {fish stock}     => {butter}         0.05000000 0.7500000  0.06666667
## [6]  {fish stock}     => {salt}           0.05000000 0.7500000  0.06666667
## [7]  {parsley}        => {flour}          0.05000000 0.7500000  0.06666667
## [8]  {butter,flour}   => {salt}           0.05000000 0.7500000  0.06666667
## [9]  {flour}          => {butter}         0.06666667 0.6666667  0.10000000
## [10] {onion}          => {salt}           0.11666667 0.6363636  0.18333333
## [11] {fish sauce}     => {lime juice}     0.05000000 0.6000000  0.08333333
## [12] {tuna}           => {milk}           0.05000000 0.6000000  0.08333333
## [13] {pepper}         => {salt}           0.05000000 0.6000000  0.08333333
## [14] {sugar}          => {fish sauce}     0.05000000 0.6000000  0.08333333
## [15] {fish sauce}     => {sugar}          0.05000000 0.6000000  0.08333333
## [16] {onion,water}    => {salt}           0.05000000 0.6000000  0.08333333
## [17] {salt,water}     => {onion}          0.05000000 0.6000000  0.08333333
## [18] {lemon juice}    => {salt}           0.08333333 0.5555556  0.15000000
## [19] {flour}          => {parsley}        0.05000000 0.5000000  0.10000000
## [20] {flour}          => {water}          0.05000000 0.5000000  0.10000000
## [21] {flour}          => {salt}           0.05000000 0.5000000  0.10000000
## [22] {water}          => {onion}          0.08333333 0.5000000  0.16666667
## [23] {water}          => {salt}           0.08333333 0.5000000  0.16666667
## [24] {butter,salt}    => {flour}          0.05000000 0.5000000  0.10000000
## [25] {onion}          => {water}          0.08333333 0.4545455  0.18333333
## [26] {milk}           => {tuna}           0.05000000 0.4285714  0.11666667
## [27] {milk}           => {butter}         0.05000000 0.4285714  0.11666667
## [28] {white wine}     => {butter}         0.05000000 0.4285714  0.11666667
## [29] {white wine}     => {salt}           0.05000000 0.4285714  0.11666667
## [30] {olive}          => {salt}           0.05000000 0.4285714  0.11666667
## [31] {butter}         => {salt}           0.10000000 0.4285714  0.23333333
## [32] {onion,salt}     => {water}          0.05000000 0.4285714  0.11666667
## [33] {salt}           => {onion}          0.11666667 0.4117647  0.28333333
## [34] {salt}           => {butter}         0.10000000 0.3529412  0.28333333
## [35] {lemon juice}    => {onion}          0.05000000 0.3333333  0.15000000
## [36] {lemon juice}    => {butter}         0.05000000 0.3333333  0.15000000
## [37] {water}          => {flour}          0.05000000 0.3000000  0.16666667
## [38] {salt}           => {lemon juice}    0.08333333 0.2941176  0.28333333
## [39] {salt}           => {water}          0.08333333 0.2941176  0.28333333
## [40] {butter}         => {flour}          0.06666667 0.2857143  0.23333333
## [41] {}               => {salt}           0.28333333 0.2833333  1.00000000
## [42] {onion}          => {lemon juice}    0.05000000 0.2727273  0.18333333
## [43] {onion}          => {butter}         0.05000000 0.2727273  0.18333333
## [44] {}               => {butter}         0.23333333 0.2333333  1.00000000
## [45] {butter}         => {leaf}           0.05000000 0.2142857  0.23333333
## [46] {butter}         => {fish stock}     0.05000000 0.2142857  0.23333333
## [47] {butter}         => {milk}           0.05000000 0.2142857  0.23333333
## [48] {butter}         => {white wine}     0.05000000 0.2142857  0.23333333
## [49] {butter}         => {lemon juice}    0.05000000 0.2142857  0.23333333
## [50] {butter}         => {onion}          0.05000000 0.2142857  0.23333333
## [51] {}               => {onion}          0.18333333 0.1833333  1.00000000
## [52] {salt}           => {pepper}         0.05000000 0.1764706  0.28333333
## [53] {salt}           => {cayenne pepper} 0.05000000 0.1764706  0.28333333
## [54] {salt}           => {fish stock}     0.05000000 0.1764706  0.28333333
## [55] {salt}           => {white wine}     0.05000000 0.1764706  0.28333333
## [56] {salt}           => {flour}          0.05000000 0.1764706  0.28333333
## [57] {salt}           => {olive}          0.05000000 0.1764706  0.28333333
## [58] {}               => {water}          0.16666667 0.1666667  1.00000000
## [59] {}               => {lemon juice}    0.15000000 0.1500000  1.00000000
## [60] {}               => {milk}           0.11666667 0.1166667  1.00000000
## [61] {}               => {white wine}     0.11666667 0.1166667  1.00000000
## [62] {}               => {olive}          0.11666667 0.1166667  1.00000000
## [63] {}               => {flour}          0.10000000 0.1000000  1.00000000
##      lift      count
## [1]  12.000000  3   
## [2]   4.285714  3   
## [3]   4.285714  3   
## [4]   2.647059  3   
## [5]   3.214286  3   
## [6]   2.647059  3   
## [7]   7.500000  3   
## [8]   2.647059  3   
## [9]   2.857143  4   
## [10]  2.245989  7   
## [11] 12.000000  3   
## [12]  5.142857  3   
## [13]  2.117647  3   
## [14]  7.200000  3   
## [15]  7.200000  3   
## [16]  2.117647  3   
## [17]  3.272727  3   
## [18]  1.960784  5   
## [19]  7.500000  3   
## [20]  3.000000  3   
## [21]  1.764706  3   
## [22]  2.727273  5   
## [23]  1.764706  5   
## [24]  5.000000  3   
## [25]  2.727273  5   
## [26]  5.142857  3   
## [27]  1.836735  3   
## [28]  1.836735  3   
## [29]  1.512605  3   
## [30]  1.512605  3   
## [31]  1.512605  6   
## [32]  2.571429  3   
## [33]  2.245989  7   
## [34]  1.512605  6   
## [35]  1.818182  3   
## [36]  1.428571  3   
## [37]  3.000000  3   
## [38]  1.960784  5   
## [39]  1.764706  5   
## [40]  2.857143  4   
## [41]  1.000000 17   
## [42]  1.818182  3   
## [43]  1.168831  3   
## [44]  1.000000 14   
## [45]  4.285714  3   
## [46]  3.214286  3   
## [47]  1.836735  3   
## [48]  1.836735  3   
## [49]  1.428571  3   
## [50]  1.168831  3   
## [51]  1.000000 11   
## [52]  2.117647  3   
## [53]  2.647059  3   
## [54]  2.647059  3   
## [55]  1.512605  3   
## [56]  1.764706  3   
## [57]  1.512605  3   
## [58]  1.000000 10   
## [59]  1.000000  9   
## [60]  1.000000  7   
## [61]  1.000000  7   
## [62]  1.000000  7   
## [63]  1.000000  6

Vemos que las reglas con confianza \(1\) son las siguientes:

\[ \mbox{(Si lleva zumo de limon)} \rightarrow \ \mbox{(Lleva salsa de pescado)} \\ \mbox{(Si lleva hojas)} \rightarrow \ \mbox{(Lleva mantequilla)} \\ \mbox{(Si lleva harina y sal)} \rightarrow \ \mbox{(Lleva mantequilla)} \]

Destacar de los resultados obtenidos que la sal aparece pocas veces siendo tan utilizada para cocinar.

Pasamos a estudiar las recetas que son picantes. Para ello cargamos el conjunto de datos que hemos creado anteriromente y que contiene solo recetas picantes.

recetas_picantes <- read.transactions("recetas_picantes.csv", sep = ",", skip = 1, rm.duplicates = FALSE)
## Warning in asMethod(object): removing duplicated items in transactions
inspect(recetas_picantes[1:2])
##     items                   
## [1] {basil,                 
##      cloves garlic,         
##      corn,                  
##      favorite seasonings,   
##      hamburger,             
##      italian seasoning,     
##      kidney beans,          
##      mild,                  
##      mushrooms,             
##      onion,                 
##      pepper,                
##      tomato sauce,          
##      uncooked pasta}        
## [2] {chicken breasts,       
##      chili,                 
##      chopped celery,        
##      chopped cilantro,      
##      corn kernels,          
##      ground roasted peanuts,
##      minced garlic,         
##      minced ginger root,    
##      pasta,                 
##      peanut,                
##      rice vinegar,          
##      salt,                  
##      sauce,                 
##      seasame seeds,         
##      sesame,                
##      snow peas,             
##      sugar,                 
##      water}

Veamos cuales son los itemsets más frecuentes en estas recetas.

itemFrequencyPlot(recetas_picantes, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")

Como en el caso anterior, el itemset más frecuente es la sal. Destacar que el segundo itemset más frecuente es el azúcar, que en un principio no parecería que tuviese mucha relación con el picante.

Pasamos a buscar reglas de asociación para las recetas picantes.

Grules_picantes <- apriori(recetas_picantes, parameter = list(supp = 0.05, conf = 0.1, minlen=2), control = list (verbose=F))
Grules_conf_picantes <- sort (Grules_picantes, by="support", decreasing=TRUE)
inspect(Grules_conf_picantes[1:30])
##      lhs                              rhs             support    confidence
## [1]  {sugar}                       => {water}         0.14285714 0.5714286 
## [2]  {water}                       => {sugar}         0.14285714 0.5714286 
## [3]  {vinegar}                     => {sugar}         0.10714286 0.7500000 
## [4]  {sugar}                       => {vinegar}       0.10714286 0.4285714 
## [5]  {sauce}                       => {sugar}         0.10714286 0.7500000 
## [6]  {sugar}                       => {sauce}         0.10714286 0.4285714 
## [7]  {sauce}                       => {water}         0.10714286 0.7500000 
## [8]  {water}                       => {sauce}         0.10714286 0.4285714 
## [9]  {minced garlic}               => {water}         0.10714286 1.0000000 
## [10] {water}                       => {minced garlic} 0.10714286 0.4285714 
## [11] {vegetable}                   => {water}         0.10714286 0.6000000 
## [12] {water}                       => {vegetable}     0.10714286 0.4285714 
## [13] {sugar}                       => {salt}          0.10714286 0.4285714 
## [14] {salt}                        => {sugar}         0.10714286 0.2727273 
## [15] {water}                       => {salt}          0.10714286 0.4285714 
## [16] {salt}                        => {water}         0.10714286 0.2727273 
## [17] {sauce,sugar}                 => {water}         0.10714286 1.0000000 
## [18] {sauce,water}                 => {sugar}         0.10714286 1.0000000 
## [19] {sugar,water}                 => {sauce}         0.10714286 0.7500000 
## [20] {flour}                       => {salt}          0.07142857 1.0000000 
## [21] {salt}                        => {flour}         0.07142857 0.1818182 
## [22] {cinnamon}                    => {vinegar}       0.07142857 1.0000000 
## [23] {vinegar}                     => {cinnamon}      0.07142857 0.5000000 
## [24] {cinnamon}                    => {sugar}         0.07142857 1.0000000 
## [25] {sugar}                       => {cinnamon}      0.07142857 0.2857143 
## [26] {cumin}                       => {garlic cloves} 0.07142857 1.0000000 
## [27] {garlic cloves}               => {cumin}         0.07142857 0.6666667 
## [28] {lemon}                       => {salt}          0.07142857 1.0000000 
## [29] {salt}                        => {lemon}         0.07142857 0.1818182 
## [30] {freshly ground black pepper} => {salt}          0.07142857 1.0000000 
##      coverage   lift     count
## [1]  0.25000000 2.285714 4    
## [2]  0.25000000 2.285714 4    
## [3]  0.14285714 3.000000 3    
## [4]  0.25000000 3.000000 3    
## [5]  0.14285714 3.000000 3    
## [6]  0.25000000 3.000000 3    
## [7]  0.14285714 3.000000 3    
## [8]  0.25000000 3.000000 3    
## [9]  0.10714286 4.000000 3    
## [10] 0.25000000 4.000000 3    
## [11] 0.17857143 2.400000 3    
## [12] 0.25000000 2.400000 3    
## [13] 0.25000000 1.090909 3    
## [14] 0.39285714 1.090909 3    
## [15] 0.25000000 1.090909 3    
## [16] 0.39285714 1.090909 3    
## [17] 0.10714286 4.000000 3    
## [18] 0.10714286 4.000000 3    
## [19] 0.14285714 5.250000 3    
## [20] 0.07142857 2.545455 2    
## [21] 0.39285714 2.545455 2    
## [22] 0.07142857 7.000000 2    
## [23] 0.14285714 7.000000 2    
## [24] 0.07142857 4.000000 2    
## [25] 0.25000000 4.000000 2    
## [26] 0.07142857 9.333333 2    
## [27] 0.10714286 9.333333 2    
## [28] 0.07142857 2.545455 2    
## [29] 0.39285714 2.545455 2    
## [30] 0.07142857 2.545455 2

Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(174\) reglas de asociación, aunque solo se muestran \(30\). Podemos observar que las reglas con mayor soporte son las siguientes:

\[ \mbox{(Si lleva azúcar)} \rightarrow \ \mbox{(Lleva agua)} \\ \mbox{(Si lleva agua)} \rightarrow \ \mbox{(Lleva azúcar)} \]

La primera regla con confianza \(1\) es la siguiente:

\[ \mbox{(Si lleva ajo molido)} \rightarrow \ \mbox{(Lleva agua)} \] Por último, veamos si podemos encontrar algúna regla interesante para todas la recetas que teníamos inicialmente.

Veamos cuales son los itemsets más frecuentes en estas recetas.

itemFrequencyPlot(recetas, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")

Los itemsets más frecuentes son la sal, el azúcar y el agua.

Pasamos a buscar reglas de asociación para todas las recetas.

Grules_todas_recetas <- apriori(recetas, parameter = list(supp = 0.05, conf = 0.1, minlen=2), control = list (verbose=F))
Grules_conf_todas_recetas <- sort (Grules_todas_recetas, by="confidence", decreasing=TRUE)
inspect(Grules_conf_todas_recetas)
##      lhs                rhs             support    confidence coverage  
## [1]  {pepper}        => {salt}          0.06245803 0.7500000  0.08327737
## [2]  {purpose flour} => {salt}          0.05305574 0.7452830  0.07118872
## [3]  {baking powder} => {salt}          0.05104097 0.7102804  0.07186031
## [4]  {vanilla}       => {sugar}         0.05104097 0.6031746  0.08462055
## [5]  {milk}          => {salt}          0.07857623 0.5679612  0.13834788
## [6]  {flour}         => {salt}          0.08126259 0.5601852  0.14506380
## [7]  {eggs}          => {salt}          0.07253190 0.5595855  0.12961719
## [8]  {eggs}          => {sugar}         0.06380121 0.4922280  0.12961719
## [9]  {sugar}         => {salt}          0.12558764 0.4908136  0.25587643
## [10] {butter}        => {salt}          0.09805238 0.4866667  0.20147750
## [11] {water}         => {salt}          0.09066488 0.4703833  0.19274681
## [12] {flour}         => {sugar}         0.06312962 0.4351852  0.14506380
## [13] {flour}         => {butter}        0.06245803 0.4305556  0.14506380
## [14] {milk}          => {butter}        0.05641370 0.4077670  0.13834788
## [15] {milk}          => {sugar}         0.05439893 0.3932039  0.13834788
## [16] {water}         => {sugar}         0.06380121 0.3310105  0.19274681
## [17] {salt}          => {sugar}         0.12558764 0.3246528  0.38683680
## [18] {butter}        => {sugar}         0.06514439 0.3233333  0.20147750
## [19] {butter}        => {flour}         0.06245803 0.3100000  0.20147750
## [20] {butter}        => {milk}          0.05641370 0.2800000  0.20147750
## [21] {sugar}         => {butter}        0.06514439 0.2545932  0.25587643
## [22] {salt}          => {butter}        0.09805238 0.2534722  0.38683680
## [23] {sugar}         => {eggs}          0.06380121 0.2493438  0.25587643
## [24] {sugar}         => {water}         0.06380121 0.2493438  0.25587643
## [25] {sugar}         => {flour}         0.06312962 0.2467192  0.25587643
## [26] {salt}          => {water}         0.09066488 0.2343750  0.38683680
## [27] {sugar}         => {milk}          0.05439893 0.2125984  0.25587643
## [28] {salt}          => {flour}         0.08126259 0.2100694  0.38683680
## [29] {salt}          => {milk}          0.07857623 0.2031250  0.38683680
## [30] {sugar}         => {vanilla}       0.05104097 0.1994751  0.25587643
## [31] {salt}          => {eggs}          0.07253190 0.1875000  0.38683680
## [32] {salt}          => {pepper}        0.06245803 0.1614583  0.38683680
## [33] {salt}          => {purpose flour} 0.05305574 0.1371528  0.38683680
## [34] {salt}          => {baking powder} 0.05104097 0.1319444  0.38683680
##      lift     count
## [1]  1.938802  93  
## [2]  1.926608  79  
## [3]  1.836124  76  
## [4]  2.357289  76  
## [5]  1.468219 117  
## [6]  1.448118 121  
## [7]  1.446567 108  
## [8]  1.923694  95  
## [9]  1.268787 187  
## [10] 1.258067 146  
## [11] 1.215973 135  
## [12] 1.700763  94  
## [13] 2.136991  93  
## [14] 2.023883  84  
## [15] 1.536694  81  
## [16] 1.293634  95  
## [17] 1.268787 187  
## [18] 1.263631  97  
## [19] 2.136991  93  
## [20] 2.023883  84  
## [21] 1.263631  97  
## [22] 1.258067 146  
## [23] 1.923694  95  
## [24] 1.293634  95  
## [25] 1.700763  94  
## [26] 1.215973 135  
## [27] 1.536694  81  
## [28] 1.448118 121  
## [29] 1.468219 117  
## [30] 2.357289  76  
## [31] 1.446567 108  
## [32] 1.938802  93  
## [33] 1.926608  79  
## [34] 1.836124  76

Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(36\) reglas de asociación. Ignorando las reglas que contienen sal, tenemos que la primera regla con mayor confianza es la siguiente:

\[ \mbox{(Si lleva vainilla)} \rightarrow \ \mbox{(Lleva azúcar)} \]

2 Ejercicio 2

En la UCI machine learning repository (en el siguiente link) encontraréis el dataset “Breast Cancer Wisconsin (Diagnostic) Data Set”. Realizar una detección de anomalías usando distintas técnicas.

2.1 Lectura y estudio de los datos

Lo primero que haremos será cargar los datos.

datos_diagnostic <- read.csv("breast-cancer-wisconsin.data", header = FALSE)
dim(datos_diagnostic)
## [1] 699  11

Vemos que tenemos 699 datos y 11 variables, a las que renombraremos y seran las siguientes:

  • Id: Número de identificación

  • Espesor_Grupo: Variable numérica que indica el expesor del grupo (rango entre 1 y 10).

  • Uniform_tam_celula: Variable numérica que indica la uniformidad del tamaño de la célula (rango entre 1 y 10).

  • Uniform_forma_celula: Variable numérica que indica la uniformidad la forma de la célula (rango entre 1 y 10).

  • Adh_marginal: Variable numérica que indica la adhesión marginal (rango entre 1 y 10).

  • Tam_celula_epi: Variable numérica que indica el tamaño de una sola célula epitelial (rango entre 1 y 10).

  • Nuc_desnudos: Variable numérica que indica los núcleos desnudos (rango entre 1 y 10).

  • Cromatina: Variable numérica que indica la cromatina suave (rango entre 1 y 10).

  • Nucleolos: Variable numérica que indica los nucleolos normales (rango entre 1 y 10).

  • Mitosis: Variable numérica que indica la mitosis (rango entre 1 y 10).

  • Clase: Esta es la variable objetivo. Es una variable factor que con \(2\) indica que una célula es benigna y con \(4\) que una célula es maligna.

names(datos_diagnostic) <- c("Id", "Espesor_Grupo", "Uniform_tam_celula",
                             "Uniform_forma_celula", "Adh_marginal", "Tam_celula_epi", 
                             "Nuc_desnudos", "Cromatina", "Nucleolos", "Mitosis", "Clase")

Veamos si este conjunto de datos contienen valores perdidos.

str(datos_diagnostic)
## 'data.frame':    699 obs. of  11 variables:
##  $ Id                  : int  1000025 1002945 1015425 1016277 1017023 1017122 1018099 1018561 1033078 1033078 ...
##  $ Espesor_Grupo       : int  5 5 3 6 4 8 1 2 2 4 ...
##  $ Uniform_tam_celula  : int  1 4 1 8 1 10 1 1 1 2 ...
##  $ Uniform_forma_celula: int  1 4 1 8 1 10 1 2 1 1 ...
##  $ Adh_marginal        : int  1 5 1 1 3 8 1 1 1 1 ...
##  $ Tam_celula_epi      : int  2 7 2 3 2 7 2 2 2 2 ...
##  $ Nuc_desnudos        : Factor w/ 11 levels "?","1","10","2",..: 2 3 4 6 2 3 3 2 2 2 ...
##  $ Cromatina           : int  3 3 3 3 3 9 3 3 1 2 ...
##  $ Nucleolos           : int  1 2 1 7 1 7 1 1 1 1 ...
##  $ Mitosis             : int  1 1 1 1 1 1 1 1 5 1 ...
##  $ Clase               : int  2 2 2 2 2 4 2 2 2 2 ...

Podemos observar que en la variable Nuc_desnudos existen valores perdidos. Veamos cuantos son.

nrow(filter(datos_diagnostic, Nuc_desnudos == "?"))
## [1] 16

Como no son muchos los valores peridos, lo que haremos será eliminarlos.

datos_diagnostic <- filter(datos_diagnostic, Nuc_desnudos != "?")

Lo que hemos de hacer ahora es pasar a numérico la variable Nuc_desnudos que se encontraba como factor y la variable Clase la pasaremos a factor.

datos_diagnostic$Nuc_desnudos <- as.numeric(datos_diagnostic$Nuc_desnudos)
datos_diagnostic$Clase <- as.factor(datos_diagnostic$Clase)

2.2 Detección de anomalías.

Comenzamos con la detección de anomalías eliminando la variable Id que no nos será de utilidad durante todo el estudio y la variable Clase que la utilizaremos al final.

datos_diagnostic_red <- datos_diagnostic[,-c(1, 11)]

Ya que todas las variables se encuentran en el mismo rango de valores observados, no escalaremos los datos.

Realizaremos ACP para reducir la dimensionalidad y poder dibujar los datos en el plano

datos_acp <- prcomp(datos_diagnostic_red)
summary(datos_acp)
## Importance of components:
##                           PC1     PC2     PC3     PC4     PC5     PC6     PC7
## Standard deviation     6.4365 2.10247 1.96247 1.76687 1.66825 1.59778 1.34319
## Proportion of Variance 0.6641 0.07086 0.06174 0.05004 0.04461 0.04092 0.02892
## Cumulative Proportion  0.6641 0.73498 0.79672 0.84677 0.89138 0.93230 0.96123
##                            PC8     PC9
## Standard deviation     1.26353 0.90676
## Proportion of Variance 0.02559 0.01318
## Cumulative Proportion  0.98682 1.00000

Hemos obtenido 6 componentes principales. Cada componente explica un porcentaje de la variación total del conjunto de datos. Ya que nuestra intención era disminuir la dimensionalidad para poder representar los datos, lo que haremos será seleccionar las 2 primeras componentes principales.

embedding <- data.table(datos_acp$x[, 1:2], Indices = c(1:nrow(datos_diagnostic_red)))

ggplot(embedding, aes(x = PC1, y = PC2)) +
    geom_point(size = 10, colour = "steelblue", alpha = 0.3) +
    geom_text(aes(label = Indices), check_overlap = TRUE) +
    theme_minimal()

Aquí podemos observar lo que podrían ser posibles outliers (como pueden ser la observación 106 o la observación 441).

Pasamos a utilizar métodos para detectar estos outliers. El primero que utilizaremos será el método DBSCAN. Lo probaremos con diferentes parámetros. Los outliers son aquellos que se encuentran en el cluster 0.

2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1 Revisar Parametros

dbscan(datos_diagnostic_red, eps = 5.5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5.5, minPts = 3
## The clustering contains 2 cluster(s) and 37 noise points.
## 
##   0   1   2 
##  37 643   3 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_5.5_3 := dbscan(datos_diagnostic_red, eps = 5.5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5, minPts = 3
## The clustering contains 2 cluster(s) and 68 noise points.
## 
##   0   1   2 
##  68 612   3 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_5_3 := dbscan(datos_diagnostic_red, eps = 5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5, minPts = 4
## The clustering contains 2 cluster(s) and 74 noise points.
## 
##   0   1   2 
##  74 606   3 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_5_4 := dbscan(datos_diagnostic_red, eps = 5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 5.5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5.5, minPts = 4
## The clustering contains 2 cluster(s) and 43 noise points.
## 
##   0   1   2 
##  43 633   7 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_5.5_4 := dbscan(datos_diagnostic_red, eps = 5.5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6, minPts = 3
## The clustering contains 1 cluster(s) and 21 noise points.
## 
##   0   1 
##  21 662 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_6_3 := dbscan(datos_diagnostic_red, eps = 6, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 6, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6, minPts = 4
## The clustering contains 1 cluster(s) and 23 noise points.
## 
##   0   1 
##  23 660 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_6_4 := dbscan(datos_diagnostic_red, eps = 6, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 3
## The clustering contains 1 cluster(s) and 11 noise points.
## 
##   0   1 
##  11 672 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_3 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 4
## The clustering contains 1 cluster(s) and 11 noise points.
## 
##   0   1 
##  11 672 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_4 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 2)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 2
## The clustering contains 1 cluster(s) and 11 noise points.
## 
##   0   1 
##  11 672 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_2 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 2)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 3
## The clustering contains 1 cluster(s) and 4 noise points.
## 
##   0   1 
##   4 679 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_3 := dbscan(datos_diagnostic_red, eps = 7, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 4
## The clustering contains 1 cluster(s) and 4 noise points.
## 
##   0   1 
##   4 679 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_4 := dbscan(datos_diagnostic_red, eps = 7, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 2)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 2
## The clustering contains 1 cluster(s) and 4 noise points.
## 
##   0   1 
##   4 679 
## 
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_2 := dbscan(datos_diagnostic_red, eps = 7, minPts = 2)$cluster]

Como podemos observar, dependiendo de los parámetros, podemos considerar 4, 11, 21, 23, 37, 43, 68 o 74 outliers. Veamos los diferentes casos representados gráficamente. El cluster con numeración 0 es el que representa los outliers.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_7_4)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=7 y minPts=4")+
  labs(color="Clusters")

Vemos que los outliers se encuentran en el interior de las observaciones.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_6.5_2)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=6.5 y minPts=2")+
  labs(color="Clusters")

A los anteriores outliers se han añadido otros como pueden ser el 99 o el 348.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_6_3)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=6 y minPts=3")+
  labs(color="Clusters")

Vemos que se siguen añadiendo observaciones como outliers a los anteriores (como puede ser la observación 480) pero de momento no se podrían distiguir a simple vista sin el uso de las etiquetas.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_6_4)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=6 y minPts=4")+
  labs(color="Clusters")

Se ha añadido a los anteriores outliers la observación 232.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_5.5_3)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=5.5 y minPts=3")+
  labs(color="Clusters")

Vemos que aquí nos separa en dos clusters a parte del cluster de los outliers. El cluster con el número 2, se encuentra en la parte inferior del gráfico, al que pertenece la observación 61.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_5.5_4)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=5.5 y minPts=4")+
  labs(color="Clusters")

En este caso, la observación 61 que antes no se consideraba outlier y generaba un cluster con otra observación, ahora se considera como outlier.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_5_3)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=5 y minPts=3")+
  labs(color="Clusters")

Con estos parámetros, se ha añadido como outlier la observación 441 que es la que podíamos pensar que era un outlier a simple vista.

ggplot(embedding, aes(x = PC1, y = PC2)) +
  geom_point(aes(colour = factor(DClusters_5_4)), size = 10, alpha = 0.3) +
  geom_text(aes(label = Indices), check_overlap = TRUE) +
  theme_minimal() + 
  ggtitle("DBSCAN con eps=5 y minPts=4")+
  labs(color="Clusters")

Se añaden algunos outliers en la parte inferior a los anteriormentes considerados.

Pasamos a utilizar el método de Maximización de expectativas (Expectation Maximization). Lo probaremos con 3,4 y 6 clusters.

#Mclust
mclust <- Mclust(datos_diagnostic_red, G = 4)

embedding[, EMClusters_4 := mclust$classification]

mclust <- Mclust(datos_diagnostic_red, G = 3)

embedding[, EMClusters_3 := mclust$classification]

mclust <- Mclust(datos_diagnostic_red, G = 6)

embedding[, EMClusters_6 := mclust$classification]

Veamos gráficamente los resultados. Los outliers son aquellos que se encuentran en el cluster 1.

ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
scale_color_manual(values=c("black", "turquoise1","green", "yellow"))+ 
ggtitle("EM con 4 clusters")+
labs(color="Clusters")

Los outliers considerados se encuentran a la derecha del gráfico, lo que parece poco coherente ya que ese gran grupo podría considerarse como un cluster.

ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_3)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
ggtitle("EM con 3 clusters")+
labs(color="Clusters")

Igual que en el caso anterior, los outliers los selecciona de la parte deecha del gráfico.

ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_6)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
scale_color_manual(values=c("black", "turquoise1","green", "yellow", "red", "orange"))+ 
ggtitle("EM con 6 clusters")+
labs(color="Clusters")

En este caso ocurre igual que con los anteriores utilizando el método EM.

Por último, utilizaremos el método LOF. Este método se basa en la densidad para detectar los outliers. Lo ejecutaremos con diferentes numeros de vecinos, que será de 3 a 8.

outlier.scores <- lof(datos_diagnostic_red, k=c(3:8))

Seleccionaremos las 10 observaciones que tengan un índice de outlier más grande en cada ejecución.

outliers = matrix(rep(0, 60), nrow =10 , ncol = 6)
for (i in 1:6) {
  outliers[,i] <- order(outlier.scores[,i], decreasing=TRUE)[1:10]
}

outliers
##       [,1] [,2] [,3] [,4] [,5] [,6]
##  [1,]    7    7    7    3    1    1
##  [2,]    8    8    8    7    3    3
##  [3,]   10   10    9    8    7    7
##  [4,]   20   20   10    9    8    8
##  [5,]   26   26   20   10    9    9
##  [6,]   33   33   30   20   10   10
##  [7,]   34   34   33   26   11   11
##  [8,]   44   44   34   30   26   12
##  [9,]   68   68   44   33   30   26
## [10,]   78   78   60   34   33   28

Podemos ver que con este método, las observaciones 7, 8 y 10 son outliers en todos los casos.

Una vez que hemos aplicado varios métodos para detectar outliers, vamos a añadir las etiquetas y ver si de verdad pueden ser outliers o no.

data <- data.table(datos_acp$x[, 1:2], Indices = c(1:nrow(datos_diagnostic_red)), Clase = datos_diagnostic$Clase)

ggplot(data, aes(x = PC1, y = PC2)) +
    geom_point(mapping = aes(color= Clase) ,size = 10, alpha = 0.3) +
    geom_text(aes(label = Indices), check_overlap = TRUE) +
    theme_minimal()

Aquí podemos ver representados los datos utilizando componentes principales donde el color representa la clase a la que pertenecen. Viendo esto y relacionandolo con los diferentes métodos empleados para detectar los outliers, se ha decidido escoger el método DBSCAN con parámetros eps=5 y minPts=3. Veamos gráficamente cuáles son los outliers que ha escogido este método utilizando el color para representar la clase a la que pertenecen.

embedding[, Clase := datos_diagnostic$Clase]
dbscan_outliers = which(embedding$DClusters_5_3==0)

ggplot(embedding[dbscan_outliers,], aes(x = PC1, y = PC2)) +
    geom_point(mapping = aes(color= Clase) ,size = 10, alpha = 0.3) +
    geom_text(aes(label = Indices), check_overlap = TRUE) +
    theme_minimal()

Observamos que este método a escogido observaciones como la 441 o 106 que podrían considerarse outliers a simple vista, pero tambien ha recogido observaciones como la 420 o la 307 que no podrían verse como outliers pero que lo son si consideramos la clase a la que pertenecen. Es por esto que se ha escogido este método con respecto a los otros.